<?php
/**
 * crcl/base
 *
 * Copyright 2013 CRCL - André Sabosch - info@crcl.de
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace crcl\base\persistance\collection;

interface IConcrete
{
  public function setReplica($sDsn);

  public function setCollection(\crcl\base\structure\ICollection $oCollection);
  public function getCollection();

  public function save();
  public function delete();

  public function beginTransaction();
  public function rollbackTransaction();
  public function commitTransaction();

  public function load($sWhere, $aBind = []);
  public function loadFromQuery(\crcl\base\database\query\ISelect $oQuery);
}

abstract class Concrete implements IConcrete
{
  public function __construct($sDsn)
  {
    $this->oDatabase = \crcl\base\Database::getInstance($sDsn);
    $this->oDsn = \crcl\base\Resource::reader($sDsn);
  }

  public function setReplica($sDsn)
  {
    $this->oDatabaseReplica = \crcl\base\Database::getInstance($sDsn);
  }

  public function setCollection(\crcl\base\structure\ICollection $oCollection)
  {
    $this->oCollection = $oCollection;
  }

  public function getCollection()
  {
    return $this->oCollection;
  }

  public function save()
  {
    $this->beginTransaction();
    try
    {
      foreach ($this->oCollection as $oItem)
      {
        $oItem->persistance()->save();
      }
    }
    catch (\Exception $e)
    {
      $this->rollbackTransaction();
      throw $e;
    }
    $this->commitTransaction();
  }

  public function delete()
  {
    $this->beginTransaction();
    try
    {
      foreach ($this->oCollection as $oItem)
      {
        $oItem->persistance()->delete();
      }
    }
    catch (\Exception $e)
    {
      //@codeCoverageIgnoreStart
      $this->rollbackTransaction();
      throw $e;
      //@codeCoverageIgnoreEnd
    }
    $this->commitTransaction();
  }

  //@codeCoverageIgnoreStart
  abstract public function beginTransaction();
  abstract public function rollbackTransaction();
  abstract public function commitTransaction();
  //@codeCoverageIgnoreEnd

  public function load($sWhere = \NULL, $aBind = [])
  {
    try
    {
      $aData = $this->oDatabaseReplica->select(
        $this->oCollection->getTable(),
        $this->oCollection->getFields(),
        $sWhere, $aBind)->get();
    }
    catch (\crcl\base\database\container\Exception $e)
    {
      if ($e->getCode() == \crcl\base\database\container\Exception::ERROR_MISSINGDATA)
      {
        $aData = array();
      }
      else
      {
        throw $e;
      }
    }

    $this->oCollection->fromArray($aData);
  }

  public function loadFromQuery(\crcl\base\database\query\ISelect $oQuery)
  {
    try
    {
      $aData = $this->oDatabaseReplica->executeSql($oQuery->toMysql())->get();
    }
    catch (\crcl\base\database\container\Exception $e)
    {
      if ($e->getCode() == \crcl\base\database\container\Exception::ERROR_MISSINGDATA)
      {
        $aData = array();
      }
      else
      {
        throw $e;
      }
    }

    $this->oCollection->fromArray($aData);
  }

  /** PROTECTED ***********************************************************************************/

  /**
   * @var \crcl\base\database\container\IConcrete
   */
  protected $oDatabase;
  protected $oDatabaseReplica;

  /**
   * @var \crcl\base\resource\reader\IDsn
   */
  protected $oDsn;
  /**
   * @var |crcl|base|structure|ICollection
   */
  protected $oCollection;
}